using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace Polymod
{
    internal class AffectedPropertiesVisitor : ExpressionVisitor
    {
        private HashSet<string> _affectedProperties = new HashSet<string>();
        private Dictionary<ParameterExpression, string> _parameters = new Dictionary<ParameterExpression, string>();
        private StringBuilder _current = new StringBuilder();

        /// <summary>
        /// Gets AffectedProperties
        /// </summary>
        public string[] AffectedProperties
        {
            get { return _affectedProperties.ToArray(); }
        }

        protected override Expression VisitMember(MemberExpression node)
        {
            var result = base.VisitMember(node);

            if (_current.Length > 0) _current.Append(".");
            _current.Append(node.Member.Name);
            _affectedProperties.Add(_current.ToString());
            return result;
        }

        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            IFormula formula;
            FormulaConversionType formulaConversionType;
            if (FormulaVisitor.IsFormula(node, out formula, out formulaConversionType))
            {
                string formulaName = _current.ToString();
                if (!string.IsNullOrEmpty(formulaName)) formulaName += ".";
                formulaName += formula.Name;
                _affectedProperties.Add(formulaName);
                //NOTE: Do not visit the formula any further, return as-is!
                return node;
            }
            return base.VisitMethodCall(node);
        }

        protected override Expression VisitLambda<T>(Expression<T> node)
        {
            foreach (var p in node.Parameters)
            {
                _parameters[p] = _current.ToString();
            }

            return base.VisitLambda<T>(node);
        }

        protected override Expression VisitParameter(ParameterExpression node)
        {
            _current = new StringBuilder(_parameters[node]);
            return base.VisitParameter(node);
        }
    }
}
